package com.hongyi.common.saToken.listener;

import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.stp.SaLoginModel;
import com.hongyi.common.framework.constant.CacheConstants;
import com.hongyi.common.framework.constant.Constants;
import com.hongyi.common.framework.domain.LoginInfoEvent;
import com.hongyi.common.framework.domain.LoginUser;
import com.hongyi.common.framework.domain.UserOnlineDTO;
import com.hongyi.common.framework.utils.DateUtils;
import com.hongyi.common.framework.utils.ip.AddressUtils;
import com.hongyi.common.framework.utils.ip.IpUtils;
import com.hongyi.common.framework.utils.ServletUtils;
import com.hongyi.common.framework.utils.spring.SpringUtils;
import com.hongyi.common.redis.utils.RedisUtils;
import com.hongyi.common.saToken.utils.LoginUtils;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

/**
 * Satoken登录用户行为 侦听器的实现
 *
 * @author DingHao
 */
@Slf4j
@AllArgsConstructor
@Component
public class UserActionListener implements SaTokenListener {

    private final SaTokenConfig tokenConfig;

    /**
     * 每次登录时触发
     */
    @Override
    public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
        log.info("用户登录："+tokenValue);
        /**
         * 创建UserAgent对象用来从HTTP请求中提取客户端的详细信息
         * 1)getHeader("User-Agent"):这是HttpServletRequest接口中的一个方法调用，用于从请求头中获取名为"User-Agent"的字段值,
         * 每个HTTP请求都会携带一系列的头部信息，其中就包括了User-Agent字段，用来标识请求发起者的身份（例如，浏览器和操作系统）
         *
         */
        final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
        //获取IP地址
        String ip = IpUtils.getIpAddr();
        //获取IP归属地址
        String address = AddressUtils.getRealAddressByIP(ip);
        // 获取客户端操作系统
        String os = userAgent.getOperatingSystem().getName();
        // 获取客户端浏览器
        String browser = userAgent.getBrowser().getName();
        // 获取登录用户信息
        LoginUser loginUser = LoginUtils.getLoginUser();

        // 记录登录用户实体,在线用户查询使用
        UserOnlineDTO userOnlineDTO = new UserOnlineDTO();
        userOnlineDTO.setIpaddr(ip);
        userOnlineDTO.setLoginLocation(address);
        userOnlineDTO.setBrowser(browser);
        userOnlineDTO.setOs(os);
        userOnlineDTO.setLoginTime(System.currentTimeMillis());
        userOnlineDTO.setTokenId(tokenValue);
        userOnlineDTO.setUserName(loginUser.getUsername());
        userOnlineDTO.setDeptName(loginUser.getDeptName());
        if(tokenConfig.getTimeout() == -1) {
            RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, userOnlineDTO);
        } else {
            RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, userOnlineDTO, (int) tokenConfig.getTimeout(), TimeUnit.SECONDS);
        }
        //系统用户记录登录信息
        if(loginUser.getUserType().equals(Constants.SYSTEM_USER)){
            //设置登录用户实体
            LoginInfoEvent loginInfoEvent = new LoginInfoEvent();
            loginInfoEvent.setUserId(loginUser.getUserId());
            loginInfoEvent.setUserName(loginUser.getUsername());
            loginInfoEvent.setDeviceType(loginUser.getDeviceType());
            loginInfoEvent.setOs(os);
            loginInfoEvent.setBrowser(browser);
            loginInfoEvent.setIpaddr(ip);
            loginInfoEvent.setLoginLocation(address);
            loginInfoEvent.setStatus(Constants.LOGIN_SUCCESS);
            loginInfoEvent.setMsg("登录成功");
            loginInfoEvent.setLoginTime(DateUtils.getNowDate());
            //发布给登录事件记录的监听方法
            SpringUtils.context().publishEvent(loginInfoEvent);
        }


    }

    /**
     * 每次注销时触发
     */
    @Override
    public void doLogout(String loginType, Object loginId, String tokenValue) {
        log.info("用户已退出登录");
    }

    /**
     * 每次被踢下线时触发
     */
    @Override
    public void doKickout(String loginType, Object loginId, String tokenValue) {

    }

    /**
     * 每次被顶下线时触发
     */
    @Override
    public void doReplaced(String loginType, Object loginId, String tokenValue) {

    }

    /**
     * 每次被封禁时触发
     */
    @Override
    public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {

    }

    /**
     * 每次被解封时触发
     */
    @Override
    public void doUntieDisable(String loginType, Object loginId, String service) {

    }

    @Override
    public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {

    }

    @Override
    public void doCloseSafe(String loginType, String tokenValue, String service) {

    }

    /**
     * 每次创建Session时触发
     */
    @Override
    public void doCreateSession(String id) {

    }

    /**
     * 每次注销Session时触发
     */
    @Override
    public void doLogoutSession(String id) {

    }

    /**
     * 每次Token续期时触发
     */
    @Override
    public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
        log.info("缓存续期了");
    }

}
